package com.game.autoTool.project.web.operate;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.game.autoTool.project.web.domain.entity.GameFunctionOperateFlow;
import com.game.autoTool.project.web.utils.HttpClientUtil;
import com.github.yitter.idgen.YitIdHelper;
import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.mouse.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 起号助手工具类
 */
public class AccountUpgraderTool {

    /**
     * 定义类变量记录上次操作时间
     */
    private static long lastOperationTime = 0;

    /**
     * 下一次操作的id
     */
    private static Long nextOperationId = null;

    /**
     * 拖动时使用
     * 实现记录拖动开始和结束坐标的功能
     */
    private static int startX;
    private static int startY;
    private static boolean isDragging = false;


    public static void main(String[] args) {
        // 创建 JFrame 对象
        JFrame frame = new JFrame("起号助手");

        // 设置窗口关闭操作，先不做默认关闭操作
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

        // 设置布局管理器
        frame.setLayout(new FlowLayout());

        // 创建一个按钮组件
        JButton startButton = new JButton("点击开始记录操作");

        // 记录窗口初始大小和位置
        final Dimension originalSize = new Dimension(500, 500);
        // 设置窗口初始大小
        frame.setSize(originalSize);

        // 使窗口居中显示
        frame.setLocationRelativeTo(null);

        // 记录窗口初始位置
        final Point originalLocation = frame.getLocation();

        // 点击时缩小窗口到指定尺寸并移动到指定位置，显示还原按钮和“执行中”文字
        startButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 倒计时 5 秒
                int countdownSeconds = 5;
                JLabel countdownLabel = new JLabel("倒计时: " + countdownSeconds + " 秒");
                // 设置倒计时标签的字体为加粗加大
                Font boldLargeFont = new Font(countdownLabel.getFont().getName(), Font.BOLD, 24);
                countdownLabel.setFont(boldLargeFont);
                frame.add(countdownLabel);
                frame.revalidate();
                frame.repaint();

                Timer countdownTimer = new Timer(1000, new ActionListener() {
                    int remainingSeconds = countdownSeconds;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        remainingSeconds--;
                        if (remainingSeconds > 0) {
                            countdownLabel.setText("执行倒计时: " + remainingSeconds + " 秒");
                        } else {
                            ((Timer) e.getSource()).stop();
                            frame.remove(countdownLabel);

                            // 启动一个新线程执行监控操作
                            Thread monitorThread = new Thread(AccountUpgraderTool::watchOperations);
                            long startTime = System.currentTimeMillis();
                            monitorThread.start();

                            // 设置窗口新的尺寸
                            frame.setSize(200, 130);
                            // 设置窗口新的坐标位置
                            frame.setLocation(1250, 53);

                            // 设置窗口始终在最前面
                            frame.setAlwaysOnTop(true);

                            // 移除原按钮
                            frame.remove(startButton);

                            // 创建并添加“已执行”标签
                            JLabel label = new JLabel("已执行: 00:00:00");
                            frame.add(label);

                            // 创建一个定时器线程来更新时长显示
                            Timer timer = new Timer(1000, new ActionListener() {
                                @Override
                                public void actionPerformed(ActionEvent e) {
                                    long elapsedTime = System.currentTimeMillis() - startTime;
                                    long seconds = elapsedTime / 1000;
                                    long hours = seconds / 3600;
                                    seconds %= 3600;
                                    long minutes = seconds / 60;
                                    seconds %= 60;

                                    String timeString = String.format("已执行: %02d:%02d:%02d", hours, minutes, seconds);
                                    label.setText(timeString);
                                }
                            });
                            timer.start();

                            // 创建还原按钮
                            JButton restoreButton = new JButton("点击中断");
                            restoreButton.addActionListener(new ActionListener() {
                                @Override
                                public void actionPerformed(ActionEvent e) {
                                    int confirm = JOptionPane.showConfirmDialog(frame,
                                            "你确定要退出吗？", "确认退出", JOptionPane.YES_NO_OPTION);
                                    if (confirm == JOptionPane.YES_OPTION) {
                                        // 恢复窗口初始大小
                                        frame.setSize(originalSize);
                                        // 恢复窗口初始位置
                                        frame.setLocation(originalLocation);
                                        // 取消窗口始终在最前面的设置
                                        frame.setAlwaysOnTop(false);

                                        // 移除还原按钮和“执行中”标签
                                        frame.remove(restoreButton);
                                        frame.remove(label);

                                        // 添加原按钮
                                        frame.add(startButton);

                                        // 重新布局和重绘窗口
                                        frame.revalidate();
                                        frame.repaint();
                                    }
                                }
                            });
                            frame.add(restoreButton);

                            // 重新布局和重绘窗口
                            frame.revalidate();
                            frame.repaint();
                        }
                    }
                });
                countdownTimer.start();
            }
        });

        // 将按钮添加到 JFrame 中
        frame.add(startButton);

        // 显示窗口
        frame.setVisible(true);

        // 监听窗口关闭事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                int confirm = JOptionPane.showConfirmDialog(frame,
                        "你确定要退出吗？", "确认退出", JOptionPane.YES_NO_OPTION);
                if (confirm == JOptionPane.YES_OPTION) {
                    try {
                        GlobalScreen.unregisterNativeHook(); // 手动释放钩子
                    } catch (NativeHookException ex) {
                        ex.printStackTrace();
                    }

                    System.out.println("关闭窗口,结束程序");
                    frame.dispose(); // 关闭窗口
                    System.exit(0); // 终止 Java 虚拟机，结束程序
                }
            }
        });
    }


    private static void watchOperations() {

        // 获取 JNativeHook 的日志记录器
        Logger logger = Logger.getLogger("org.jnativehook");

        // 创建一个 ConsoleHandler，并设置为禁用级别
        ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setLevel(Level.OFF);

        // 将日志处理器添加到 JNativeHook 的日志记录器
        logger.addHandler(consoleHandler);

        try {
            // 关闭JNativeHook的调试日志输出
            Logger.getLogger(GlobalScreen.class.getPackage().getName()).setLevel(Level.SEVERE);

            // 注册全局钩子
            GlobalScreen.registerNativeHook();
        } catch (NativeHookException e) {
            e.printStackTrace();
            System.exit(1);
        }

        GlobalScreen.addNativeMouseMotionListener(new NativeMouseInputListener() {

            @Override
            public void nativeMouseMoved(NativeMouseEvent e) {
                //不需要记录移动了,数量太多了,可以后期自己做计算
//                System.out.printf("[移动] X=%d, Y=%d\n", e.getX(), e.getY());
//                saveEvent(2, e.getX(), e.getY());
            }

            @Override
            public void nativeMouseDragged(NativeMouseEvent e) {
                //在拖动的时候记录开始坐标,在释放的时候判断是否有赋值,有的话直接插入拖动的结束时候,如果没有赋值,则不记录

                //操作类型(11键盘按下12键盘释放,21鼠标移动,22鼠标拖动,23鼠标左键点击,24鼠标右键点击,25鼠标向上滚动,26鼠标向下滚动)
                if (!isDragging) {
                    System.out.printf("[拖动] X=%d, Y=%d, Button=%d\n", e.getX(), e.getY(), e.getButton());
                    saveEvent(22, e.getX(), e.getY());

                    startX = e.getX();
                    startY = e.getY();
                    isDragging = true;
                }
            }


            @Override
            public void nativeMousePressed(NativeMouseEvent e) {
                // 这个不能用,用的下面的
                System.out.println("按下事件被触发【1】");
                System.out.printf("[按下] X=%d, Y=%d, Button=%d\n", e.getX(), e.getY(), e.getButton());
            }

            @Override
            public void nativeMouseClicked(NativeMouseEvent e) {
                // 这个不能用,用的下面的
                System.out.println("点击事件被触发【1】");
                System.out.printf("[点击] X=%d, Y=%d, Button=%d\n", e.getX(), e.getY(), e.getButton());
            }

            @Override
            public void nativeMouseReleased(NativeMouseEvent e) {
                // 这个不能用,用的下面的
                System.out.println("释放事件被触发【1】");
                System.out.printf("[释放] X=%d, Y=%d, Button=%d\n", e.getX(), e.getY(), e.getButton());
            }
        });

        GlobalScreen.addNativeMouseListener(new NativeMouseListener() {

            @Override
            public void nativeMouseClicked(NativeMouseEvent e) {
                //e.getButton() 1是左键,2是右键
                System.out.printf("[点击] X=%d, Y=%d, Button=%d\n", e.getX(), e.getY(), e.getButton());

                //操作类型(11键盘按下12键盘释放,21鼠标移动,22鼠标拖动,23鼠标左键点击,24鼠标右键点击,25鼠标向上滚动,26鼠标向下滚动)
                if (e.getButton() == 1) {//e.getButton() 1是左键,2是右键
                    saveEvent(23, e.getX(), e.getY());
                } else {
                    saveEvent(24, e.getX(), e.getY());
                }

            }


            //nativeMousePressed 和 nativeMouseReleased 是配套使用的，它们共同描述了鼠标按键的完整交互过程-拖动
            //因为点击和按下-释放重叠,不好判定是不是拖动,所以直接用上面的
            @Override
            public void nativeMousePressed(NativeMouseEvent e) {
//                System.out.println("按下事件被触发");
//                //Button 1 代表左键,2代表右键
//                System.out.printf("[按下] X=%d, Y=%d, Button=%d\n", e.getX(), e.getY(), e.getButton());
//
//                //操作类型(11键盘按下12键盘释放,21鼠标移动,22鼠标拖动,23鼠标左键点击,24鼠标右键点击,25鼠标向上滚动,26鼠标向下滚动)
//                saveEvent(2, e.getX(), e.getY());
            }


            @Override
            public void nativeMouseReleased(NativeMouseEvent e) {
//                System.out.println("释放事件被触发");
//                System.out.printf("[释放] X=%d, Y=%d, Button=%d\n", e.getX(), e.getY(), e.getButton());
//                saveEvent(3, e.getX(), e.getY());

                //配合拖动来使用,记录拖动结束的位置
                //操作类型(11键盘按下12键盘释放,21鼠标移动,22鼠标拖动,23鼠标左键点击,24鼠标右键点击,25鼠标向上滚动,26鼠标向下滚动)
                if (isDragging) {
                    System.out.printf("[释放] X=%d, Y=%d, Button=%d\n", e.getX(), e.getY(), e.getButton());
                    saveEvent(22, e.getX(), e.getY());

                    isDragging = false;
                }
            }

        });


        // 添加滚轮监听器
        GlobalScreen.addNativeMouseWheelListener(new NativeMouseWheelListener() {
            @Override
            public void nativeMouseWheelMoved(NativeMouseWheelEvent e) {
                // 滚轮方向：wheelRotation > 0 表示向下滚，< 0 表示向上滚
                String direction = e.getWheelRotation() > 0 ? "向下" : "向上";
                System.out.printf("[滚轮] 方向=%s, 滚动量=%d, 类型=%s\n",
                        direction,
                        Math.abs(e.getWheelRotation()),
                        e.getScrollType() == NativeMouseWheelEvent.WHEEL_UNIT_SCROLL ? "单位滚动" : "块滚动"
                );

                //操作类型(11键盘按下12键盘释放,21鼠标移动,22鼠标拖动,23鼠标左键点击,24鼠标右键点击,25鼠标向上滚动,26鼠标向下滚动)
                if (e.getWheelRotation() <= 0) {
                    saveEvent(25, e.getX(), e.getY());
                } else {
                    saveEvent(26, e.getX(), e.getY());
                }
            }

        });

        // 关闭钩子时释放资源
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                GlobalScreen.unregisterNativeHook();
            } catch (NativeHookException e) {
                e.printStackTrace();
            }
        }));

        // 保持程序运行
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                break;
            }
        }
    }


    /**
     * 插入到数据库中
     *
     * @param type 操作类型(11键盘按下12键盘释放,21鼠标移动,22鼠标拖动,23鼠标左键点击,24鼠标右键点击,25鼠标向上滚动,26鼠标向下滚动)
     * @param x    x坐标
     * @param y    y坐标
     */
    private static void saveEvent(int type, int x, int y) {


        GameFunctionOperateFlow event = new GameFunctionOperateFlow();
        //如果没有下一步的id 说明是第一条记录,id就自己生成,下一步的id为下一条的主键
        if (ObjectUtil.isEmpty(nextOperationId)) {
            nextOperationId = YitIdHelper.nextId();
            event.setId(YitIdHelper.nextId());

            event.setNextId(nextOperationId);

        } else {
            event.setId(nextOperationId);

            nextOperationId = YitIdHelper.nextId();

            event.setNextId(nextOperationId);
        }

        event.setFunctionTaskId(1213246765L);
        event.setFlowDesc("起号助手");

        event.setOperateType(type);
        event.setTargetX(x);
        event.setTargetY(y);

        //两个操作间隔时间
        if (lastOperationTime != 0) {
            // 计算时间间隔（当前时间 - 上次操作时间）
            long currentTime = System.currentTimeMillis();

            System.out.println("时间为" + lastOperationTime);

            int stayTime = (int) (currentTime - lastOperationTime); // 转为毫秒
            event.setStayTime(stayTime);

            // 更新上次操作时间为当前时间
            lastOperationTime = currentTime;
        }else {
            event.setStayTime(0);

            // 更新上次操作时间为当前时间
            lastOperationTime = System.currentTimeMillis();
        }

        event.setIsDel(0);
        event.setCreateTime(DateUtil.now());
        event.setUpdateTime(DateUtil.now());

        System.out.println("执行结果数据为" + JSONObject.toJSONString(event));
        String ret = HttpClientUtil.sendPost("http://127.0.0.1:28888/flow/record", JSONObject.parseObject(JSONObject.toJSONString(event)));
        System.out.println("执行结果为" + ret);

    }

}
